package com.puzzlebazar.client.main.view;

import java.util.Iterator;
import java.util.Vector;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.puzzlebazar.client.main.model.PuzzleListInfo;
import com.puzzlebazar.client.main.model.PuzzleListInfoSearch;
import com.puzzlebazar.client.main.model.PuzzleListInfoImpl.ListType;
import com.puzzlebazar.client.util.ConcurrentVector;
import com.puzzlebazar.client.util.TextUtil;

public class SearchView extends Composite {
	
	
	private final TextBox searchBox = new TextBox();
	
	private final RadioButton editable = new RadioButton( "state", "Editable" );
	private final RadioButton playable = new RadioButton( "state", "Playable" );
	private final RadioButton all = new RadioButton( "state", "All" );

	private final ConcurrentVector<SearchCallback> callbacks = 
		new ConcurrentVector<SearchCallback>();

	public SearchView() {
		
		Label label = new Label( "Puzzle genre" );
		searchBox.setWidth( "100%" );		

		Button searchButton = new Button( "Search" );
		Button cancelButton = new Button( "Cancel" );
		
		searchButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				executeSearch( buildListInfo() );
			}
		});	

		cancelButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				executeCancel();
			}
		});		
		
		HorizontalPanel searchPanel = new HorizontalPanel();
		searchPanel.setWidth( "100%" );
		searchPanel.add( label );
		searchPanel.add( searchBox );
		searchPanel.setCellWidth( label, "100px" );
		
		HorizontalPanel statePanel = new HorizontalPanel();
		statePanel.add( all );
		statePanel.add( editable );
		statePanel.add( playable );
	
		HorizontalPanel buttonPanel = new HorizontalPanel();
		buttonPanel.add( searchButton );
		buttonPanel.add( cancelButton );
		statePanel.setCellWidth( searchButton, "100px" );
		statePanel.setCellWidth( cancelButton, "100px" );
		
		VerticalPanel mainPanel = new VerticalPanel();
		mainPanel.setStylePrimaryName( "mainContent" );
		mainPanel.setWidth( "100%" );
		mainPanel.add( searchPanel );
		mainPanel.add( statePanel );
		mainPanel.add( buttonPanel );
		
		initWidget( mainPanel );		
	}

	/**
	 * Clears all the states of the dialog box so that it can be reused
	 */
	public void resetState() {
		searchBox.setText( "" );
		all.setValue(true);
		DeferredCommand.addCommand( new Command() {
			@Override
			public void execute() {
				searchBox.setFocus( true );
			}			
		});
	}
	
	/**
	 * Adds a callback to be executed when the user searches
	 * 
	 * @param callback The callback to add
	 */
	public void addCallback( final SearchCallback callback ) {
		callbacks.add( callback );			
	}

	/**
	 * Remove a callback added with addCallback()
	 * 
	 * @param callback The callback to remove
	 */
	public void removeCallback( SearchCallback callback ) {
		callbacks.remove( callback );		
	}


	/**
	 * Creates a PuzzleListInfo class based on the user's entry in the search view. 
	 * 
	 * @return A newly constructed PuzzleListInfo
	 */
	private PuzzleListInfo buildListInfo() {
		Vector<String> genreList = TextUtil.split( searchBox.getText(), "," );
		ListType listType = ListType.ALL_PUZZLES;
		if( editable.getValue() ) listType = ListType.EDITABLE_PUZZLES;
		if( playable.getValue() ) listType = ListType.PLAYABLE_PUZZLES;		
		return new PuzzleListInfoSearch( listType, genreList );
	}
	
	public interface SearchCallback {

		/**
		 * Called whenever the Search button is clicked
		 * 
		 * @param searchListInfo The information regarding the puzzles to list
		 */
		public void search( PuzzleListInfo searchListInfo );
		
		/**
		 * Called whenever the cancel button is clicked
		 */
		public void cancel();
	}	

	/**
	 * Execute all callbacks associated with the Search button 
	 *
	 * @param searchListInfo The information regarding the puzzles to list
	 */
	private void executeSearch( PuzzleListInfo searchListInfo ) {
		
		for (Iterator<SearchCallback> iterator = callbacks.iterator(); iterator.hasNext();) {
			SearchCallback callback = iterator.next();
			callback.search( searchListInfo );			
		}		

	}

	/**
	 * Execute all callbacks associated with the Cancel button 
	 */
	private void executeCancel() {
		
		for (Iterator<SearchCallback> iterator = callbacks.iterator(); iterator.hasNext();) {
			SearchCallback callback = iterator.next();
			callback.cancel();			
		}		

	}
}
